package com.zhiqian.community.service;

import com.zhiqian.community.entity.Event;
import com.zhiqian.community.entity.Page;
import com.zhiqian.community.event.EventProducer;
import com.zhiqian.community.util.CommunityConstant;
import com.zhiqian.community.util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class FollowService implements CommunityConstant {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserService userService;
    @Autowired
    private EventProducer eventProducer;


    /**
     * 关注或取消关注
     *
     * @param entityType
     * @param entityId
     * @param userId
     */
    public void doFollow(int entityType, Integer entityId, Integer userId) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        int followStatus = selectFollowStatus(entityType, entityId, userId);
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations redisOperations) throws DataAccessException {
                redisOperations.multi();
                if (followStatus==0) {
                    redisOperations.opsForZSet().add(followeeKey, entityId, System.currentTimeMillis());
                    redisOperations.opsForZSet().add(followerKey, userId, System.currentTimeMillis());
                }else {
                    redisOperations.opsForZSet().remove(followeeKey, entityId);
                    redisOperations.opsForZSet().remove(followerKey, userId);
                }
                return redisOperations.exec();
            }
        });
        if (followStatus==0){
            Event followEvent = createFollowEvent(entityId, userId);
            eventProducer.fireEvent(followEvent);
        }
    }

    /**
     * 查询用户对某实体的关注状态
     *
     * @param entityType
     * @param entityId
     * @param userId
     * @return 1:关注 0：未关注
     */
    public int selectFollowStatus(int entityType, Integer entityId, Integer userId) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        Double score = redisTemplate.opsForZSet().score(followeeKey, entityId);
        Double score1 = redisTemplate.opsForZSet().score(followerKey, userId);
        return score != null && score1 != null ? 1 : 0;
    }

    /**
     * 查看用户的关注数量
     *
     * @param entityType
     * @param userId
     * @return
     */
    public long selectFolloweeCount(int entityType, Integer userId) {
        String followeeKey = RedisKeyUtil.getFolloweeKey(userId, entityType);
        Long count = redisTemplate.opsForZSet().zCard(followeeKey);
        return count == null ? 0 : count;
    }

    /**
     * 查看实体的粉丝数量
     *
     * @param entityType
     * @param entityId
     * @return
     */
    public long selectFollowerCount(int entityType, Integer entityId) {
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        Long count = redisTemplate.opsForZSet().zCard(followerKey);
        return count == null ? 0 : count;
    }

    /**
     * 查询实体的粉丝列表
     * @param entityType
     * @param entityId
     * @param userId
     * @return
     */
    public List<Map<String,Object>> selectFollowerList(int entityType, Integer entityId,Integer userId,Page page){
        List<Map<String,Object>> result = new ArrayList();
        String followerKey = RedisKeyUtil.getFollowerKey(entityType, entityId);
        Set<Integer> followers = redisTemplate.opsForZSet().reverseRange(followerKey, page.getOffset(), page.getOffset()+page.getLimit()-1);
        followers.stream().forEach(followerId -> {
            Map<String, Object> map = new HashMap<>(3);
            map.put("user",userService.getUserById(followerId));
            Double date = redisTemplate.opsForZSet().score(followerKey, followerId);
            map.put("followTime",new Date(date.longValue()));
            map.put("followStatus",selectFollowStatus(ENTITY_TYPE_USER,followerId,userId));
            result.add(map);
        });
        return result;
    }

    /**
     * 查询用户的关注列表
     * @param targetId
     * @param userId
     * @return
     */
    public List<Map<String,Object>> selectFolloweeList(Integer targetId, Integer userId, Page page){
        List<Map<String,Object>> result = new ArrayList();
        String followeeKey = RedisKeyUtil.getFolloweeKey(targetId, ENTITY_TYPE_USER);
        Set<Integer> followees = redisTemplate.opsForZSet().reverseRange(followeeKey, page.getOffset(), page.getOffset()+page.getLimit()-1);
        followees.stream().forEach(followeeId -> {
            Map<String, Object> map = new HashMap<>(3);
            map.put("user",userService.getUserById(followeeId));
            Double date = redisTemplate.opsForZSet().score(followeeKey, followeeId);
            Date time = new Date(date.longValue());
            map.put("followTime",time);
            map.put("followStatus",selectFollowStatus(ENTITY_TYPE_USER,followeeId,userId));
            result.add(map);
        });
        return result;
    }

    private Event createFollowEvent(Integer targetId,Integer userId){
        Event event = new Event();
        event.setTopic(TOPIC_FOLLOW);
        event.setSourceId(userId);
        event.setTargetId(targetId);
        return event;
    }

}
